﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using StackExchange.Redis;

namespace Redis.StackExchange
{
    public class MyRedisDbClient
    {
        private readonly IDatabase _redisDb;
        private readonly string _host;
        private readonly int _port;
        private readonly int _dbIndex;

        public MyRedisDbClient(string host, int port, int dbIndex, string password = "")
        {
            _host = host;
            _port = port;
            _dbIndex = dbIndex;
            var redisClient = MyRedisClient.GetInstance(_host, _port, password);
            _redisDb = redisClient.GetDatabase(_dbIndex);
        }

        #region 对象JSON化

        /// <summary>
        /// 把object对象JSON化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        private string ObjectToJson<T>(T obj)
        {
            return JsonConvert.SerializeObject(obj);
        }

        #endregion

        #region 还原Redis中的JSON化对象

        /// <summary>
        /// 还原Redis中的JSON化对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="json"></param>
        /// <returns></returns>
        private T JsonToObject<T>(string json)
        {
            if (json == null)
                json = ObjectToJson(default(T));
            return JsonConvert.DeserializeObject<T>(json);
        }

        #endregion

        public bool KeyRename(string oldRedisKey, string newRedisKey)
        {
            var x = _redisDb.KeyRename(oldRedisKey, newRedisKey);
            return x;
        }

        public bool KeyExists(string redisKey)
        {
            var x = _redisDb.KeyExists(redisKey);
            return x;
        }

        public void FlushDb()
        {
            var server = _redisDb.Multiplexer.GetServer(_host, _port);
            server.FlushDatabase(_dbIndex);
        }

        public List<string> GetAllKeyLike(string key, bool leftStar = false, bool rightStar = false)
        {
            var left = leftStar ? "*" : "";
            var right = rightStar ? "*" : "";
            key = $"{left}{key}{right}";

            var server = _redisDb.Multiplexer.GetServer(_host, _port);
            var list = server.Keys(_dbIndex, key);
            return list.Select(k => k.ToString()).ToList();
        }

        #region String

        public bool StringAddOrUpdate<T>(string redisKey, T value)
        {
            var jsonValue = ObjectToJson(value);
            var x = _redisDb.StringSet(redisKey, jsonValue);

            return x;
        }

        public bool StringAddOrUpdate<T>(string redisKey, T value, TimeSpan liveTime)
        {
            var jsonValue = ObjectToJson(value);
            var x = _redisDb.StringSet(redisKey, jsonValue, liveTime);

            return x;
        }

        public bool StringAddIfNotExists<T>(string redisKey, T value)
        {
            var jsonValue = ObjectToJson(value);
            var x = _redisDb.StringSet(redisKey, jsonValue, null, When.NotExists);
            return x;
        }

        public bool StringUpdateIfExists<T>(string redisKey, T value)
        {
            var jsonValue = ObjectToJson(value);
            var x = _redisDb.StringSet(redisKey, jsonValue, null, When.Exists);
            return x;
        }
        
        public string StringGet(string redisKey)
        {
            var strValue = _redisDb.StringGet(redisKey);
            return strValue;
        }

        public T StringGet<T>(string redisKey)
        {
            var jsonValue = StringGet(redisKey);
            var result = JsonToObject<T>(jsonValue);
            return result;
        }

        public bool StringDelete(string redisKey)
        {
            var x = _redisDb.KeyDelete(redisKey);
            return x;
        }

        public long StringIncrement(string redisKey,long value =1)
        {
            var x = _redisDb.StringIncrement(redisKey, value);
            return x;
        }

        public long StringDecrement(string redisKey, long value = 1)
        {
            var x = _redisDb.StringDecrement(redisKey, value);
            return x;
        }

        public double StringIncrement(string redisKey, double value)
        {
            var x = _redisDb.StringIncrement(redisKey, value);
            return x;
        }

        public double StringDecrement(string redisKey, double value)
        {
            var x = _redisDb.StringDecrement(redisKey, value);
            return x;
        }

        #endregion

        #region List

        public long ListRightPush<T>(string redisKey, T value)
        {
            var jsonValue = ObjectToJson(value);
            var currentListLength = _redisDb.ListRightPush(redisKey, jsonValue);
            return currentListLength;
        }

        public T ListRightPop<T>(string redisKey)
        {
            var jsonValue = _redisDb.ListRightPop(redisKey);
            var result = JsonToObject<T>(jsonValue);
            return result;
        }

        public long ListLeftPush<T>(string redisKey, T value)
        {
            var jsonValue = ObjectToJson(value);
            var currentListLength = _redisDb.ListLeftPush(redisKey, jsonValue);
            return currentListLength;
        }

        public T ListLeftPop<T>(string redisKey)
        {
            var jsonValue = _redisDb.ListLeftPop(redisKey);
            var result = JsonToObject<T>(jsonValue);
            return result;
        }

        public long ListRemove<T>(string redisKey, T value)
        {
            var jsonValue = ObjectToJson(value);
            var currentListLength = _redisDb.ListRemove(redisKey, jsonValue);
            return currentListLength;
        }

        public long ListLength(string redisKey)
        {
            var currentListLength = _redisDb.ListLength(redisKey);
            return currentListLength;
        }

        public bool ListDelete(string redisKey)
        {
            var x = _redisDb.KeyDelete(redisKey);
            return x;
        }

        #endregion

        #region Hash

        public bool HashSet<T>(string redisKey, string hashKey, T value)
        {
            var jsonValue = ObjectToJson(value);
            var x = _redisDb.HashSet(redisKey, hashKey, jsonValue);
            return x;
        }

        public bool HashSetIfNotExists<T>(string redisKey, string hashKey, T value)
        {
            var jsonValue = ObjectToJson(value);
            var x = _redisDb.HashSet(redisKey, hashKey, jsonValue, When.NotExists);
            return x;
        }

        public ConcurrentDictionary<string, T> HashGet<T>(string redisKey)
        {
            var hash = _redisDb.HashGetAll(redisKey);
            var dic = new ConcurrentDictionary<string, T>();
            foreach (var kv in hash)
            {
                var key = kv.Name;
                var value = JsonToObject<T>(kv.Value);
                dic.TryAdd(key, value);
            }
            return dic;
        }

        public T HashGet<T>(string redisKey, string hashKey)
        {
            var jsonValue = _redisDb.HashGet(redisKey, hashKey);
            var result = JsonToObject<T>(jsonValue);
            return result;
        }

        public long HashLength(string redisKey)
        {
            var hashLength = _redisDb.HashLength(redisKey);
            return hashLength;
        }

        public bool HashExists(string redisKey, string hashKey)
        {
            var isExists = _redisDb.HashExists(redisKey, hashKey);
            return isExists;
        }

        public bool HashDelete(string redisKey, string hashKey)
        {
            var x = _redisDb.HashDelete(redisKey, hashKey);
            return x;
        }

        public bool HashDelete(string redisKey)
        {
            var x = _redisDb.KeyDelete(redisKey);
            return x;
        }

        public long HashIncrement(string redisKey, string hashKey, long value = 1)
        {
            var x = _redisDb.HashIncrement(redisKey, hashKey, value);
            return x;
        }

        public long HashDecrement(string redisKey, string hashKey, long value = 1)
        {
            var x = _redisDb.HashDecrement(redisKey, hashKey, value);
            return x;
        }

        public double HashIncrement(string redisKey, string hashKey, double value)
        {
            var x = _redisDb.HashIncrement(redisKey, hashKey, value);
            return x;
        }

        public double HashDecrement(string redisKey, string hashKey, double value)
        {
            var x = _redisDb.HashDecrement(redisKey, hashKey, value);
            return x;
        }

        #endregion


    }
}
